package dbPhase.hypeerweb;

/**
 * NodeState is an abstract class to be used to create states for the nodes.
 *
 * @pre Domain: <br>
 * 		Standard is 0
 * 		UpPointing is 1
 * 		DownPointing is 2
 * 		HypercubeCap is 3
 * 		Terminal is 4
 *
 *
 */
public abstract class NodeState {

	/* StandardNodeState.STATE_ID = 0
	 * UpPointingNodeState.STATE_ID = 1
	 * DownPointingNodeState.STATE_ID = 2
	 * HypercubeCapState.STATE_ID = 3
	 * TerminalNodeState.STATE_ID = 4*/

	/*
	 * 	The add node algorithm. (As explained to me by the TA)  -- Javid Pack
	 *
	 * Find is called on a random node. Find is used to find a starting place on the upper layer. newNode is node to be added.
	 * 	Standard: determine biggest neghbor or fold, call biggest.find(newNode)
	 * 	Terminal: determine smallest downpointer, call it smallesetdp, and call smallestdb.search(this.parent.id, smallestdp.id, newnode)
	 *  Up: determine biggest neghbor or fold, call biggest.find(newNode)
	 *  Down: if has a neighbor bigger, then call biggestneghbor.find(new), otherwise determine smallest downpointer, and call smallestdb.search(this.parent.id, smallestdp.id, newnode)
	 *  Cap: call fold.addchild(newNode)
	 *
	 * Search is used to find insertion point, limiting search between lowerbound and upperbound.
	 *  Standard: SHOULD NOT BE CALLED, throw error
	 * 	Terminal: determine smallest downpointer, call it smallesetdp, and call smallestdb.search(this.parent.id, smallestdp.id, newnode)
	 *  Up: Find biggest uppointer, if uppointer.child.id is greater than lb, then call biggestuppointer.search(biggestuppointer.child.id, ub, newnode)
	 *  	otherwise, if lb cant change: using smallest neghbor that is childless as ub, call smallchildlessneghibor.serch(lb, ub, newnode)
	 *  Down: determine smallest downpointer, call it smallesetdp, and call smallestdb.search(this.parent.id, smallestdp.id, newnode)
	 *  Cap: SHOULD NOT BE CALLED, throw error
	 *
	 * At beginning of any search call, if this.webid == lb+1, then call this.addChild(newNode);
	 */

	/* Node State Conversion Rules
	 * Terminal node:  on add node, if has dp, change to dp, if
	 * ....?
	 *
	 *
	 * Populating new Node Rules:
	 *
	 * Neighbors: parent, parent's uppointers
	 * Down Pointers: parents neighbors whose WebId > parent's WebId
	 * ....?
	 *
	 * Child is largest neighbor
	 * Parent is smallest neighbor
	 * */
//	public static final int STATE_ID = -1;


	/**
	 * getStateId returns the id of the state that a particular node is in.
	 *
	 * @pre none
	 */
	public abstract int getStateId();

	/**
	 * find uses the node passed in to continue to find a node closer to the end goal node.
	 *
	 * @pre the node passed in is not null and is closer each time to find the end goal node.
	 *
	 * @param thisNode - the current node to continue to operate on.
	 *
	 * @return a node that is closer to the end goal.
	 */
	public abstract Node find(Node thisNode );


	/**
	 * search determines if the terminal node has been found and returns it if it has or it continues the
	 * search with the bounds it is given.
	 *
	 * @pre lb < ub and thisNode is not null
	 *
	 * @param lb - lowerbound
	 * @param ub - upperbound
	 * @param thisNode -the current node
	 * @return another node closer in the search to the terminal node.
	 */
	public abstract Node search(int lb, int ub, Node thisNode );

	@Override
	public abstract java.lang.String toString();

	/**
	 * getNodeState
	 * @pre the id is 0-4
	 * @param id - the integer representation of the desired state.
	 * @return the singleton of the state that matches the id passed in.
	 */
	public static NodeState getNodeState(int id) {
		switch (id) {
		case(0):
			return StandardNodeState.getSingleton();
		case(1):
			return UpPointingNodeState.getSingleton();
		case(2):
			return DownPointingNodeState.getSingleton();
		case(3):
			return HypercubeCapState.getSingleton();
		case(4):
			return TerminalNodeState.getSingleton();
		default:
			System.err.println("Swtich Error!");
		}
		return null;
	}

	/**
	 * findDP uses the node passed in to continue to find a node closer to the deletion point node.
	 *
	 * @pre the node passed in is not null and is closer each time to find the deletion point node.
	 *
	 * @param thisNode - the current node to continue to operate on.
	 *
	 * @return a node that is closer to the deletion point node.
	 */
	public abstract Node findDP(Node thisNode);

	/**
	 * searchDP determines if the deletion point node has been found and returns it if it has or it continues the
	 * search with the bounds it is given.
	 *
	 * @pre lb < ub and thisNode is not null
	 *
	 * @param lb - lowerbound
	 * @param ub - upperbound
	 * @param thisNode -the current node
	 * @return another node closer in the search to the deletion point node.
	 */
	public abstract Node searchDP(int lb, int ub, Node thisNode);

}
